package com.cn.demo.config;

import com.cn.demo.utils.DateUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Date;


//@Component
//@Aspect
public class MyAspect {

    @Pointcut(value = "execution(* com.cn.demo.service.*.*(..))")
    public void pointcut() {
    }

    /**
     * 前置通知：执行目标方法前 触发
     */
    @Before(value = "pointcut()")
    public void methodBefore(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("[" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss")
                + "]前置通知：方法名：" + methodName + "，参数" + Arrays.asList(joinPoint.getArgs()));
    }

    /**
     * 后置通知：执行目标方法后触发
     */
    @After(value = "pointcut()")
    public void methodAfter(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("[" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss")
                + "]后置通知：方法名：" + methodName + "，参数" + Arrays.asList(joinPoint.getArgs()));
    }

    /**
     * 返回通知：目标方法执行完并返回参数后触发。
     */
    @AfterReturning(value = "pointcut()", returning = "result")
    public void methodAfterReturning(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("[" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss")
                + "]返回通知：方法名：" + methodName + "，" +
                "参数" + Arrays.asList(joinPoint.getArgs()) + "，" +
                "返回结果：");
        if (result instanceof String[]) {
            Arrays.stream((String[]) result).forEach(System.out::println);
        } else {
            System.out.println(result);
        }
    }
    /**
     * 异常通知：目标方法抛出异常后触发
     */
    @AfterThrowing(value = "pointcut()", throwing = "ex")
    public void methodExceptionOccurred(JoinPoint joinPoint, Exception ex) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("[" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss")
                + "]异常通知：方法名：" + methodName + "，参数" + Arrays.asList(joinPoint.getArgs()) + "，异常信息：" + ex.getMessage());
    }

    /**
     * 环绕通知，围绕着方法执行
     * 环绕通知需要携带ProceedingJoinPoint类型的参数
     * 环绕通知类似于动态代理的全过程：ProceedingJoinPoint类型的参数可以决定是否执行目标方法。
     * 而且环绕通知必须有返回值，返回值即为目标方法的返回值
     */
    @Around(value = "pointcut()")
    public Object methodAround(ProceedingJoinPoint proceedingJoinPoint) {
        Object result = null;
        String methodName = proceedingJoinPoint.getSignature().getName();
        System.out.println("[" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss")
                + "]环绕通知：方法名：" + methodName + "，参数" + Arrays.asList(proceedingJoinPoint.getArgs()));
        //执行目标方法
        try {
            result = proceedingJoinPoint.proceed();
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
        return result;
    }

}
